1. Technical Field
The present invention relates generally to Java™ virtual machines (“Java” is a trademark of Sun Microsystems, Inc.), and more particularly to analyzing thread dumps in a Java virtual machine.
2. Description of Related Art
Ever since the rise of the Internet, the use of the Java Platform, from Sun Microsystems, Inc., by the software development community has increased significantly. It is partly due to the advantages of its own Java Programming Language, which is object-oriented, distributed, multithreaded and portable. An Object-oriented programming language such as Java programming language provides programmers flexibility to create modules that do not need to be changed when a new type of object is added; this enables an object to inherit the characteristics of another object, which contributes to reusable software. As a result, development time can be shortened and developers can spend more time on other aspects of the software life cycle.
However, a more important feature of the Java Platform is its portability. Portability means the ability to run a program on any platform. A platform is a hardware or software environment in which a program runs, for example, Windows 2000, Linux, Solaris, and Mac OS. The Java Platform provides such capability by using two mechanisms: the Java Virtual Machine, known as JVM, and the Java Application Programming Interface, known as Java API. The Java virtual machine is an abstract computing machine. Like a real computing machine, it has an instruction set and manipulates various memory areas at run time. The Java virtual machine does not assume any particular implementation technology, host hardware, or host operating system. It is not inherently interpreted, but can just as well be implemented by compiling its instruction set to that of a silicon CPU. It may also be implemented in microcode or directly in silicon.
JVM works in the Java Platform as depicted in FIGS. 3A-C: a program file, with a .java extension 302, is first compiled by the compiler 304 to translate it into Java bytecodes. Java bytecodes are platform independent codes interpreted by the interpreter on the Java Platform. It is in binary format stored in a .class file 306. The interpreter 308 then parses and runs the Java bytecode instruction on the computer 310. In turn the program is only compiled once and interpreted each time the program is executed. The use of Java bytecodes helps to make “write once, run anywhere” possible.
The second component of the Java Platform is the Java API. It is a collection of software components that provide many capabilities, such as a graphical user interface (GUI) widgets. The Java API is grouped into libraries of related classes and interfaces called packages. The programmers primarily use the Java API to write the program. As illustrated in FIG. 3B, the Java API acts as an interface between the program written by the programmer and the Java Virtual Machine, which executes the program in a hardware-based platform by interpreting the Java bytecodes corresponding to the program.
As discussed above, another important feature of the Java Platform is its support for multithreading at the language level. FIG. 3C depicts multithreading in a block diagram. A thread is a basic unit of program execution. At any given time, a program can have several threads running concurrently, each thread performing a different job. The Java language accomplishes such tasks by synchronization, which coordinates activities and data access among multiple threads. The Java Virtual Machine uses a mechanism named Monitors to support synchronization. There is a lock associated with every object or resource in a Java environment. If multiple threads want to operate on the same object, a monitor is used to provide a way for the threads to independently work on the object without interfere with each other. When a thread wants to acquire a shared object, a code segment within a program identified with the synchronized keyword is used to associate a lock with every object that has synchronized code. Once the lock for the object is obtained by performing a lock operation in the JVM, the body of the code segment is then executed. The thread becomes the owner of the object 314, hence an active thread 318. If during the time of execution of the active thread another thread wants to claim ownership of the monitor, it must wait in the entry set 312 of the object along with the other threads already waiting. Once the active thread is finished executing the critical region, it can release the monitor in two ways: it can complete the execution or it can issue a wait command. In the prior case, the thread can simply exit the monitor 320. Alternatively, by issuing the wait command, the active thread becomes a waiting thread in the wait set 316. If the former owner did not issue a notify command before it releases the monitor, only threads in the entry set will compete to acquire the monitor. If the former owner did execute a notify, then the entry set along with any threads in the wait set will compete to acquire the monitor. If a thread in the wait state wins, it then exits the wait set and reacquires the monitor. Once again, it becomes an active thread.
Sometimes when a program executes concurrent thread operations, a deadlock situation may occur. A deadlock occurs when one thread, for example thread t1, owns resource A and wants to acquire resource B, which is owned by thread t2. In order for t1 to access resource B, t1 has to wait until t2 release the monitor for resource B. However, if t2 is waiting for t1 to release the monitor for resource A before it will release the monitor for resource B. Thread t2 will also stuck in a wait state. This creates a situation where neither thread can proceed. Furthermore, if more than two threads are involved in the similar manner, a circular wait condition will occur as each thread holds the resources that other threads want in a cycle. There is also another situation where a thread can be waiting on the resources that it currently owns. This introduces an infinite wait condition since the thread continues to wait for itself.
Deadlock is a well-known problem in the concurrent programming environment. Various approaches have been suggested by existing literature to minimize the issue. A majority of the approaches focus on deadlock avoidance, by educating programmers on how to apply programming techniques that will avoid deadlock. For example, in some systems a resource ordering technique is proposed to ensure the locks are obtained in the same order by all threads. This is accomplished by associating some numeric values to each object and each thread obtains the lock in the order of increasing numbers. That way a strict order is imposed when obtaining locks and a comparison is made at runtime to ensure the order. This method of prevention will only be successful when the programmer applies the principle in the software design along with catching exception when the problem arises. The problem becomes more complex as deadlock occurs during application runtime and no exception is caught at that moment.
Another approach is by using a profiler agent to interact with a currently running JVM. For example, Sun Microsystems has an emerging standard named JVMPI. The JVMPI is a two-way function call interface between the Java virtual machine and an in-process profiler agent. On one hand, the virtual machine notifies the profiler agent of various events, corresponding to, for example, heap allocation, thread start, etc. On the other hand, the profiler agent issues controls and requests for more information through the JVMPI. For example, the profiler agent can turn on/off a specific event notification, based on the needs of the profiler front-end. This provides a way to detect deadlock by looking at the events triggered by the JVM and provides the profiler agent control over certain events. However, this technology only serves the purpose when the JVM is currently running. It does not provide any type of user analysis at the front end to illustrate problem areas.
As shown in the above example approaches, none currently provide the capability to analyze potential deadlocks in large-scale application such as IBM Websphere Application server, where hundreds of threads are involved. Further, none currently process the information for the user to identify potential infinite wait conditions; and none performs analysis of the JVM in an offline mode while the JVM is not running. Therefore, it would be advantageous to have an improved method and apparatus for analyzing thread dumps of a live JVM and in an offline mode to detect deadlocks that are stuck in a circular and infinite wait conditions. It would also be beneficial if such method and apparatus provides analysis across different JVMs, for example, IBM JVM.